c086216038638be144fd2a3b5bed73dde06ca0ba
[openwrt/openwrt.git] /
1 From fcd1c53b460aa39cfd15f842126af62b27a4fad5 Mon Sep 17 00:00:00 2001
2 From: Lei Wei <quic_leiwei@quicinc.com>
3 Date: Tue, 2 Apr 2024 18:28:42 +0800
4 Subject: [PATCH 13/50] net: pcs: Add 2500BASEX interface mode support to IPQ
5 UNIPHY PCS driver
6
7 2500BASEX mode is used when PCS connects with QCA8386 switch in a fixed
8 2500M link. It is also used when PCS connectes with QCA8081 PHY which
9 works at 2500M link speed. In addition, it can be also used when PCS
10 connects with a 2.5G SFP module.
11
12 Change-Id: I3fe61113c1b3685debc20659736a9488216a029d
13 Signed-off-by: Lei Wei <quic_leiwei@quicinc.com>
14 ---
15 drivers/net/pcs/pcs-qcom-ipq-uniphy.c | 95 +++++++++++++++++++++++++++
16 1 file changed, 95 insertions(+)
17
18 --- a/drivers/net/pcs/pcs-qcom-ipq-uniphy.c
19 +++ b/drivers/net/pcs/pcs-qcom-ipq-uniphy.c
20 @@ -25,6 +25,7 @@
21 #define PCS_MODE_SGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x4)
22 #define PCS_MODE_QSGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x1)
23 #define PCS_MODE_PSGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x2)
24 +#define PCS_MODE_SGMII_PLUS FIELD_PREP(PCS_MODE_SEL_MASK, 0x8)
25 #define PCS_MODE_XPCS FIELD_PREP(PCS_MODE_SEL_MASK, 0x10)
26 #define PCS_MODE_AN_MODE BIT(0)
27
28 @@ -282,6 +283,24 @@ static void ipq_unipcs_get_state_sgmii(s
29 state->pause |= MLO_PAUSE_RX;
30 }
31
32 +static void ipq_unipcs_get_state_2500basex(struct ipq_uniphy_pcs *qunipcs,
33 + int channel,
34 + struct phylink_link_state *state)
35 +{
36 + u32 val;
37 +
38 + val = ipq_unipcs_reg_read32(qunipcs, PCS_CHANNEL_STS(channel));
39 +
40 + state->link = !!(val & PCS_CHANNEL_LINK_STS);
41 +
42 + if (!state->link)
43 + return;
44 +
45 + state->speed = SPEED_2500;
46 + state->duplex = DUPLEX_FULL;
47 + state->pause |= MLO_PAUSE_TXRX_MASK;
48 +}
49 +
50 static void ipq_unipcs_get_state_usxgmii(struct ipq_uniphy_pcs *qunipcs,
51 struct phylink_link_state *state)
52 {
53 @@ -373,6 +392,12 @@ static int ipq_unipcs_config_mode(struct
54 PCS_MODE_SEL_MASK | PCS_MODE_AN_MODE,
55 PCS_MODE_PSGMII);
56 break;
57 + case PHY_INTERFACE_MODE_2500BASEX:
58 + rate = 312500000;
59 + ipq_unipcs_reg_modify32(qunipcs, PCS_MODE_CTRL,
60 + PCS_MODE_SEL_MASK,
61 + PCS_MODE_SGMII_PLUS);
62 + break;
63 case PHY_INTERFACE_MODE_USXGMII:
64 case PHY_INTERFACE_MODE_10GBASER:
65 rate = 312500000;
66 @@ -450,6 +475,22 @@ err:
67 return ret;
68 }
69
70 +static int ipq_unipcs_config_2500basex(struct ipq_uniphy_pcs *qunipcs,
71 + phy_interface_t interface)
72 +{
73 + int ret;
74 +
75 + if (qunipcs->interface != interface) {
76 + ret = ipq_unipcs_config_mode(qunipcs, interface);
77 + if (ret)
78 + return ret;
79 +
80 + qunipcs->interface = interface;
81 + }
82 +
83 + return 0;
84 +}
85 +
86 static int ipq_unipcs_config_usxgmii(struct ipq_uniphy_pcs *qunipcs,
87 unsigned int neg_mode,
88 phy_interface_t interface)
89 @@ -522,6 +563,21 @@ static unsigned long ipq_unipcs_clock_ra
90 return rate;
91 }
92
93 +static unsigned long ipq_unipcs_clock_rate_get_gmiiplus(int speed)
94 +{
95 + unsigned long rate = 0;
96 +
97 + switch (speed) {
98 + case SPEED_2500:
99 + rate = 312500000;
100 + break;
101 + default:
102 + break;
103 + }
104 +
105 + return rate;
106 +}
107 +
108 static unsigned long ipq_unipcs_clock_rate_get_xgmii(int speed)
109 {
110 unsigned long rate = 0;
111 @@ -566,6 +622,9 @@ ipq_unipcs_link_up_clock_rate_set(struct
112 case PHY_INTERFACE_MODE_PSGMII:
113 rate = ipq_unipcs_clock_rate_get_gmii(speed);
114 break;
115 + case PHY_INTERFACE_MODE_2500BASEX:
116 + rate = ipq_unipcs_clock_rate_get_gmiiplus(speed);
117 + break;
118 case PHY_INTERFACE_MODE_USXGMII:
119 case PHY_INTERFACE_MODE_10GBASER:
120 rate = ipq_unipcs_clock_rate_get_xgmii(speed);
121 @@ -627,6 +686,21 @@ pcs_adapter_reset:
122 PCS_CHANNEL_ADPT_RESET);
123 }
124
125 +static void ipq_unipcs_link_up_config_2500basex(struct ipq_uniphy_pcs *qunipcs,
126 + int channel,
127 + int speed)
128 +{
129 + /* 2500BASEX do not support autoneg and do not need to
130 + * configure PCS speed, only reset PCS adapter here.
131 + */
132 + ipq_unipcs_reg_modify32(qunipcs, PCS_CHANNEL_CTRL(channel),
133 + PCS_CHANNEL_ADPT_RESET,
134 + 0);
135 + ipq_unipcs_reg_modify32(qunipcs, PCS_CHANNEL_CTRL(channel),
136 + PCS_CHANNEL_ADPT_RESET,
137 + PCS_CHANNEL_ADPT_RESET);
138 +}
139 +
140 static void ipq_unipcs_link_up_config_usxgmii(struct ipq_uniphy_pcs *qunipcs,
141 int speed)
142 {
143 @@ -669,6 +743,17 @@ static void ipq_unipcs_link_up_config_us
144 XPCS_USXG_ADPT_RESET);
145 }
146
147 +static int ipq_unipcs_validate(struct phylink_pcs *pcs,
148 + unsigned long *supported,
149 + const struct phylink_link_state *state)
150 +{
151 + /* In-band autoneg is not supported for 2500BASEX */
152 + if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
153 + phylink_clear(supported, Autoneg);
154 +
155 + return 0;
156 +}
157 +
158 static void ipq_unipcs_get_state(struct phylink_pcs *pcs,
159 struct phylink_link_state *state)
160 {
161 @@ -682,6 +767,9 @@ static void ipq_unipcs_get_state(struct
162 case PHY_INTERFACE_MODE_PSGMII:
163 ipq_unipcs_get_state_sgmii(qunipcs, channel, state);
164 break;
165 + case PHY_INTERFACE_MODE_2500BASEX:
166 + ipq_unipcs_get_state_2500basex(qunipcs, channel, state);
167 + break;
168 case PHY_INTERFACE_MODE_USXGMII:
169 ipq_unipcs_get_state_usxgmii(qunipcs, state);
170 break;
171 @@ -716,6 +804,8 @@ static int ipq_unipcs_config(struct phyl
172 case PHY_INTERFACE_MODE_PSGMII:
173 return ipq_unipcs_config_sgmii(qunipcs, channel,
174 neg_mode, interface);
175 + case PHY_INTERFACE_MODE_2500BASEX:
176 + return ipq_unipcs_config_2500basex(qunipcs, interface);
177 case PHY_INTERFACE_MODE_USXGMII:
178 return ipq_unipcs_config_usxgmii(qunipcs,
179 neg_mode, interface);
180 @@ -748,6 +838,10 @@ static void ipq_unipcs_link_up(struct ph
181 ipq_unipcs_link_up_config_sgmii(qunipcs, channel,
182 neg_mode, speed);
183 break;
184 + case PHY_INTERFACE_MODE_2500BASEX:
185 + ipq_unipcs_link_up_config_2500basex(qunipcs,
186 + channel, speed);
187 + break;
188 case PHY_INTERFACE_MODE_USXGMII:
189 ipq_unipcs_link_up_config_usxgmii(qunipcs, speed);
190 break;
191 @@ -761,6 +855,7 @@ static void ipq_unipcs_link_up(struct ph
192 }
193
194 static const struct phylink_pcs_ops ipq_unipcs_phylink_ops = {
195 + .pcs_validate = ipq_unipcs_validate,
196 .pcs_get_state = ipq_unipcs_get_state,
197 .pcs_config = ipq_unipcs_config,
198 .pcs_link_up = ipq_unipcs_link_up,